﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;

namespace YArchitech.Revit
{
	public class CurveElementNode
	{
		public CurveElementNode(Element element, XYZ point, double deviation)
		{
			this.curveElement = (element as CurveElement);
			IList<XYZ> allPoints = this.GetAllPoints();
			this.SetInOutPoint(allPoints, point);
			this.InitialNode(this.pointOut, deviation);
		}

		public CurveElementNode(Element element, XYZ point)
		{
			this.curveElement = (element as CurveElement);
			IList<XYZ> allPoints = this.GetAllPoints();
			this.SetInOutPoint(allPoints, point);
		}

		private void InitialNode(XYZ point, double deviation)
		{
			this.subCurveElems = this.GetSubCENodes(point, deviation);
		}

		private void SetInOutPoint(IList<XYZ> listPnt, XYZ point)
		{
			double num = listPnt[0].DistanceTo(point);
			double num2 = listPnt[1].DistanceTo(point);
			if (num > num2)
			{
				this.pointIn = listPnt[1];
				this.pointOut = listPnt[0];
				return;
			}
			this.pointIn = listPnt[0];
			this.pointOut = listPnt[1];
		}

		public IList<XYZ> GetAllPoints()
		{
			List<XYZ> list = new List<XYZ>();
			LocationCurve locationCurve = this.curveElement.Location as LocationCurve;
			((ICollection<XYZ>)list).Add(locationCurve.Curve.GetEndPoint(0));
			((ICollection<XYZ>)list).Add(locationCurve.Curve.GetEndPoint(1));
			return list;
		}

		public IList<CurveElement> GetSubCENodes(XYZ point, double deviation)
		{
			IList<CurveElement> list = new List<CurveElement>();
			XYZ xyz = new XYZ(point.X - deviation / 2.0, point.Y - deviation / 2.0, point.Z - deviation / 2.0);
			XYZ xyz2 = new XYZ(point.X + deviation / 2.0, point.Y + deviation / 2.0, point.Z + deviation / 2.0);
			BoundingBoxIntersectsFilter boundingBoxIntersectsFilter = new BoundingBoxIntersectsFilter(new Outline(xyz, xyz2));
			IList<Element> list2 = new FilteredElementCollector(this.curveElement.Document).OfCategory(BuiltInCategory.OST_Lines).WherePasses(boundingBoxIntersectsFilter).ToElements();
			if (list2.Count > 1)
			{
				foreach (Element element in list2)
				{
					if (!element.Id.IntegerValue.Equals(this.curveElement.Id.IntegerValue))
					{
						CurveElement curveElement = element as CurveElement;
						Curve curve = (curveElement.Location as LocationCurve).Curve;
						if (curve.GetEndPoint(0).IsAlmostEqualTo(point, 0.0001) || curve.GetEndPoint(1).IsAlmostEqualTo(point, 0.0001))
						{
							list.Add(curveElement);
						}
					}
				}
				this.lineCount = list.Count;
				if (list.Count > 1)
				{
					this.subElementNodes = new List<CurveElementNode>();
				}
			}
			return list;
		}

		public CurveElement GetOutCurveElement()
		{
			CurveElement result = null;
			if (this.subCurveElems == null)
			{
				return result;
			}
			if (this.subCurveElems.Count == 1)
			{
				result = this.subCurveElems[0];
			}
			else if (this.subCurveElems.Count > 1)
			{
				XYZ xyz = this.pointIn.Subtract(this.pointOut).Normalize();
				foreach (CurveElement curveElement in this.subCurveElems)
				{
					Curve curve = (curveElement.Location as LocationCurve).Curve;
					XYZ xyz2 = curve.GetEndPoint(0).Subtract(curve.GetEndPoint(1)).Normalize();
					result = curveElement;
					double num = 0.087266462599716474;
					if (Math.Abs(xyz.AngleTo(xyz2) - Math.PI*.5) < num || Math.Abs(xyz.AngleTo(-1.0 * xyz2) - 4.71238898038469) < num)
					{
						result = curveElement;
						break;
					}
				}
			}
			return result;
		}

		public void GetRootNode(ref CurveElementNode curveNode, CurveElementNode bottomNode)
		{
			if (bottomNode.PreView != null)
			{
				curveNode = bottomNode.preView;
			}
			else
			{
				curveNode = bottomNode;
			}
			this.GetRootNode(ref curveNode, curveNode);
		}

		public void GetBottomNode(ref CurveElementNode curveNode)
		{
			if (curveNode.Next != null)
			{
				curveNode = curveNode.preView;
			}
			this.GetBottomNode(ref curveNode);
		}

		public CurveElementNode AnalysisCurveNode(CurveElementNode rootNode)
		{
			if (rootNode == null)
			{
				return rootNode;
			}
			while (rootNode != null && rootNode.Next != null)
			{
				XYZ xyz = rootNode.PointOut.Subtract(rootNode.PointIn).Normalize();
				CurveElementNode curveElementNode = rootNode.Next;
				if (!curveElementNode.PointOut.Subtract(curveElementNode.PointIn).Normalize().IsAlmostEqualTo(xyz, 0.0001))
				{
					break;
				}
				rootNode.PointOut = new XYZ(curveElementNode.PointOut.X, curveElementNode.PointOut.Y, curveElementNode.PointOut.Z);
				if (curveElementNode.Next == null)
				{
					rootNode.Next = null;
					return rootNode;
				}
				rootNode.Next = curveElementNode.Next;
				curveElementNode.Next.PreView = rootNode;
			}
			if (rootNode.Next != null)
			{
				CurveElementNode rootNode2 = rootNode.Next;
				this.AnalysisCurveNode(rootNode2);
			}
			return rootNode;
		}

		public CurveElement CurveElement
		{
			get
			{
				return this.curveElement;
			}
			set
			{
				this.curveElement = value;
			}
		}

		public XYZ PointIn
		{
			get
			{
				return this.pointIn;
			}
			set
			{
				this.pointIn = value;
			}
		}

		public XYZ PointOut
		{
			get
			{
				return this.pointOut;
			}
			set
			{
				this.pointOut = value;
			}
		}

		public IList<CurveElement> SubCurveElems
		{
			get
			{
				return this.subCurveElems;
			}
			set
			{
				this.subCurveElems = value;
			}
		}

		public IList<CurveElementNode> SubElementNodes
		{
			get
			{
				return this.subElementNodes;
			}
			set
			{
				this.subElementNodes = value;
			}
		}

		public CurveElementNode PreView
		{
			get
			{
				return this.preView;
			}
			set
			{
				this.preView = value;
			}
		}

		public CurveElementNode Next
		{
			get
			{
				return this.next;
			}
			set
			{
				this.next = value;
			}
		}

		public int LineCount
		{
			get
			{
				return this.lineCount;
			}
			set
			{
				this.lineCount = value;
			}
		}

		private CurveElement curveElement;

		private XYZ pointIn;

		private XYZ pointOut;

		private IList<CurveElement> subCurveElems;

		private IList<CurveElementNode> subElementNodes;

		private CurveElementNode preView;

		private CurveElementNode next;

		private int lineCount = -1;
	}
}
